﻿using System;
using System.Linq;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;
using System.Collections.Generic;
using System.Diagnostics;
using System.ComponentModel;
using System.IO;

namespace RunAllTestsInSolutionTask.Reporting
{
    public class ExportCodeMetrics : Task
    {
        [Required]
        public string CodeMetrics
        {
            get;
            set;
        }

        [Required]
        public string SolutionFile
        {
            get;
            set;
        }

        [Required]
        public string OutputFile { get; set; }

        public string Parmaters { get;  set; }

        public string Configuration { get; set; }

        public ITaskItem[] ExcludeDlls { get; set; }
        

        public override bool Execute()
        {
            try
            {
                if (string.IsNullOrEmpty(Configuration))
                    Configuration = "Debug";
                IList<string> dlls = SolutionParser.GetAllDlls(SolutionFile, Configuration);
                dlls = RemoveExcludedDlls(dlls);

                ProcessStartInfo info = CreateProcessStartInfo(dlls);
                Console.WriteLine("Exporting Metrics:");
                Console.WriteLine(info.FileName + " " + info.Arguments);

                Process testRunnerProc = new Process();
                testRunnerProc.StartInfo = info;
                testRunnerProc.StartInfo.UseShellExecute = false;
                testRunnerProc.StartInfo.RedirectStandardOutput = true;
                testRunnerProc.StartInfo.RedirectStandardError = true;

                testRunnerProc.OutputDataReceived += new DataReceivedEventHandler(this.PrintToConsole);
                testRunnerProc.ErrorDataReceived += new DataReceivedEventHandler(this.PrintToConsole);

                testRunnerProc.Start();
                System.Threading.Thread.Sleep(1000);
                testRunnerProc.BeginOutputReadLine();
                testRunnerProc.BeginErrorReadLine();
                testRunnerProc.WaitForExit();

                return WasRunSuccesful();
                
                //return 0 == testRunnerProc.ExitCode;
            }
            catch (Win32Exception)
            {
                Console.WriteLine("Couldn't locate Metrics.exe. Check that path to metrics.exe is correct");
                throw;
            }
        }

        private bool WasRunSuccesful()
        {

            var path = Path.GetDirectoryName(Path.GetFullPath(OutputFile));
            var file = Path.Combine(path, "MultipleFiles.lastcodemetricssucceeded");
            return File.Exists(file);
        }
        private IList<string> RemoveExcludedDlls(IList<string> dlls)
        {
            if (ExcludeDlls == null)
                return dlls;
            var excludedDllNames = ConvertExcludedToStrings();

            var result = new List<string>();
            foreach (var dll in dlls)
            {
                var dllName = Path.GetFileName(dll);
                if (!excludedDllNames.Contains(dllName))
                    result.Add(dll);
            }
            return result;
        }
        private IList<string> ConvertExcludedToStrings()
        {
            var names = new List<string>();
            foreach (var item in ExcludeDlls)
            {
                names.Add(item.ItemSpec);
            }
            return names;
        }
        private void PrintToConsole(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (string.IsNullOrEmpty(outLine.Data))
                return;
            if (this.BuildEngine != null)
            {

                this.Log.LogMessage(outLine.Data);
            }
            else
            {
                Console.WriteLine(outLine.Data);
            }
        }

        virtual protected ProcessStartInfo CreateProcessStartInfo(IList<string> testdlls)
        {

            var processInfo = new ProcessStartInfo();
            processInfo.FileName = CodeMetrics;
            foreach (var dll in testdlls)
            {
                processInfo.Arguments += @"/f:" + "\"" + dll + "\" ";
            }
            processInfo.Arguments += "/out:"+this.OutputFile+" /gac /sf";
            processInfo.Arguments += this.Parmaters;
            return processInfo;
        }


    }
}
